using System;
using Gtk;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;

using ShaderCompiler.Core;

public partial class MainWindow: Gtk.Window
{
	public MainWindow()
	: base(Gtk.WindowType.Toplevel)
	{
		Build();
		
string code =
@"
using ShaderCompiler.Core;

namespace ShadersCS
{
	public sealed class Drop : ShaderI
	{
		[VSInput(VSInputTypes.Position, 0)]
		public Vector3 Position_VS;
		[VSInput(VSInputTypes.UV, 0)]
		public Vector2 UV_VS;

		[VSOutputPSInput(VSOutputPSInputTypes.Position, 0)]
		public Vector4 Position_VSPS;
		[VSOutputPSInput(VSOutputPSInputTypes.InOut, 0)]
		public Vector2 UV_VSPS;

		[PSOutput(PSOutputTypes.Color, 0)]
		public Vector4 Color_PS;

		public Vector2 Location;
		public Matrix4 testMat;

		[ShaderMethod(ShaderMethodTypes.VS)]
		public void mainVS()
		{
			Position_VSPS = new Vector4(Position_VS.xy + Location, Position_VS.z, 1);
			UV_VSPS = Position_VS.xy;
			Vector4 vec = testMat.Multiply(new Vector4(0, 0, 0, 0));
		}

		[ShaderMethod(ShaderMethodTypes.PS)]
		public void mainPS()
		{
			double dis = SL.Distance(Location, UV_VSPS);
			SL.Clip(.1 - dis);

			Color_PS = new Vector4(0, 0, 1, 0);
		}
	}
}
";
		
		textview2.Buffer.Text = code;
		compileButton.Clicked += HandleCompileButtonClicked;
		
		try
		{
			using (var file = new FileStream("Settings.txt", FileMode.OpenOrCreate, FileAccess.Read))
			using (var reader = new StreamReader(file))
			{
				projDir.Text = reader.ReadLine();
				shaderOutput.Text = reader.ReadLine();
				compileTypes.Active = int.Parse(reader.ReadLine());
				shaderOutputTypes.Active = int.Parse(reader.ReadLine());
			}
		}
		catch{}
	}
	
	protected void OnDeleteEvent(object sender, DeleteEventArgs a)
	{
		using (var file = new FileStream("Settings.txt", FileMode.Create, FileAccess.Write))
		using (var writer = new StreamWriter(file))
		{
			writer.WriteLine(projDir.Text);
			writer.WriteLine(shaderOutput.Text);
			writer.WriteLine(compileTypes.Active.ToString());
			writer.WriteLine(shaderOutputTypes.Active.ToString());
		}
	
		Application.Quit();
		a.RetVal = true;
	}
	
	private void compileFromMemory()
	{
		var c = new Compiler(textview2.Buffer.Text, CompilerCodeSources.Memory);
		
		CompilerOutputs outputType = CompilerOutputs.GL2;
		switch (shaderOutputTypes.ActiveText)
		{
			case ("Direct3D10"):
				outputType = CompilerOutputs.D3D10;
				break;
			case ("Direct3D9"):
				outputType = CompilerOutputs.D3D9;
				break;
			case ("XNA"):
				outputType = CompilerOutputs.XNA;
				break;
			case ("OpenGL3"):
				outputType = CompilerOutputs.GL3;
				break;
			case ("OpenGL2"):
				outputType = CompilerOutputs.GL2;
				break;
			case ("GLES2"):
				outputType = CompilerOutputs.GLES2;
				break;
			default: throw new Exception("Unsuported Memory Type.");
		}
		
		textview3.Buffer.Text = c.CompileFromMemory(textview2.Buffer.Text, outputType);
	}
	private void compileProjectType(Compiler compiler, string type)
	{
		string tag = null;
		CompilerOutputs outputType = CompilerOutputs.GL2;
		switch (type)
		{
			case ("Direct3D10"):
				tag = "D3D10_";
				outputType = CompilerOutputs.D3D10;
				break;
			case ("Direct3D9"):
				tag = "D3D9_";
				outputType = CompilerOutputs.D3D9;
				break;
			case ("XNA"):
				tag = "XNA_";
				outputType = CompilerOutputs.XNA;
				break;
			case ("OpenGL3"):
				tag = "GL3_";
				outputType = CompilerOutputs.GL3;
				break;
			case ("OpenGL2"):
				tag = "GL2_";
				outputType = CompilerOutputs.GL2;
				break;
			case ("GLES2"):
				tag = "GLES2_";
				outputType = CompilerOutputs.GLES2;
				break;
		}
		
		compiler.FileTag = tag;
		compiler.Compile(shaderOutput.Text, outputType);
	}
	
	private void compileProject()
	{
		var compiler = new Compiler(projDir.Text, CompilerCodeSources.Project);
		
		if (shaderOutputTypes.ActiveText == "All")
		{
			compileProjectType(compiler, "Direct3D10");
			compileProjectType(compiler, "Direct3D9");
			compileProjectType(compiler, "XNA");
			compileProjectType(compiler, "OpenGL3");
			compileProjectType(compiler, "OpenGL2");
			compileProjectType(compiler, "GLES2");
		}
		else
		{
			compileProjectType(compiler, shaderOutputTypes.ActiveText);
		}
	}

	void HandleCompileButtonClicked (object sender, EventArgs e)
	{
		try
		{
			if (compileTypes.ActiveText == "Memory") compileFromMemory();
			if (compileTypes.ActiveText == "Project") compileProject();
		}
		catch (Exception ex)
		{
			Console.WriteLine(ex.Message);
			textview3.Buffer.Text = ex.Message;
		}
	}
}
